#include <sys/sockets.h>
#include <netdb.h>
#include "net/ethernet.h"
#include "string.h"
#include "Wed_framework.h"
int getsockopt(int        sockfd,
               int        level,
               int        optname,
               void      *optval,
               socklen_t *optlen){
    return 0;
}

int setsockopt(int         sockfd,
               int         level,
               int         optname,
               const void *optval,
               socklen_t   optlen){
    return 0;
}

static uint8_t __g_buf[1024];
static uint32_t buf_len = 0;
extern int tsw_data_recv(uint8_t *p_buf_data);
int recv(int s, void *mem, size_t len, int flags){
    int len_ret;

    len_ret = tsw_data_recv(mem);
    if (len_ret > 0) {
        return len_ret;
    }
    return 0;
}

int recvfrom(int s, void *mem, size_t len, int flags,
              struct sockaddr *from, socklen_t *fromlen){
    return 0;
}

int send(int s, const void *data, size_t size, int flags){
    return 0;
}

extern int tsw_send_data(uint8_t *p_buf_data, uint32_t data_len);
extern void Wed_kprintf(const char *fmt, ...);
extern int tsw_recv_data_chk(void);
int sendto(int s, const void *data, size_t size, int flags,
            const struct sockaddr *to, socklen_t tolen){
    int                ret;
    struct Wed_netdev *p_dev = NULL;

    memset(__g_buf, 0, 1024);
    memcpy(__g_buf, data, size);
    buf_len = size;

//    for (int i = 0; i < size; i++) {
//        Wed_kprintf("0x%x ", __g_buf[i]);
//        if (i % 8 == 0) {
//            Wed_kprintf("\r\n");
//        }
//    }

    p_dev = Wed_netdev_find_by_name("tsn2");
    if (p_dev == NULL) {
        return -1;
    }

    ret = Wed_netdev_raw_output(p_dev, (uint8_t *)data, size);
    if (ret == 0) {
        return size;
        //tsw_recv_data_chk();
    } else {
        Wed_kprintf("tsw send failed()%d\r\n", ret);
    }
    return ret;
}

int accept(int s, struct sockaddr *addr, socklen_t *addrlen){
    return 0;
}


int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                char *host, size_t hostlen,
                char *serv, size_t servlen,
                int flags){
    return 0;
}

void freeaddrinfo(struct addrinfo *res){

}

typedef struct ip4_addr {
    uint32_t addr;
} ip_addr_t;

int getaddrinfo(const char              *node,
                const char              *service,
                const struct addrinfo   *hints,
                struct addrinfo        **res){
//    struct addrinfo *p_ai    = NULL;
//    int              ai_family;
//    int              port_nr = 0;
//    int              err;
//    ip_addr_t        addr;
//
//    if (res == NULL) {
//        return -1;
//    }
//    *res = NULL;
//    if ((node == NULL) && (service == NULL)) {
//        return -1;
//    }
//
//
//
//    struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
//    /* set up sockaddr */
//    inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
//    sa4->sin_family = AF_INET;
//    sa4->sin_len    = sizeof(struct sockaddr_in);
//    sa4->sin_port   = lwip_htons((u16_t)port_nr);
//    ai->ai_family   = AF_INET;
//    if (hints != NULL) {
//      ai_family = hints->ai_family;
//      if ((ai_family != AF_UNSPEC) && (ai_family != AF_INET)) {
//          return -1;
//      }
//    } else {
//      ai_family = AF_UNSPEC;
//    }
//
//    if (service != NULL) {
//      /* service name specified: convert to port number
//       * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
//        port_nr = atoi(service);
//        if ((port_nr <= 0) || (port_nr > 0xffff)) {
//            return -1;
//        }
//    }
//
//    if (node != NULL) {
//        /* service location specified, try to resolve */
//        if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
//            /* no DNS lookup, just parse for an address string */
//            if (!ipaddr_aton(node, &addr)) {
//                return -1;
//            }
//        } else {
//            err = netconn_gethostbyname_addrtype(node, &addr, NETCONN_DNS_IPV4);
//            if (err != 0) {
//                return -1;
//            }
//        }
//    } else {


    return 0;
}

uint32_t htonl(uint32_t n){
    return ((((n) & (uint32_t)0x000000ffUL) << 24) | \
            (((n) & (uint32_t)0x0000ff00UL) <<  8) | \
            (((n) & (uint32_t)0x00ff0000UL) >>  8) | \
            (((n) & (uint32_t)0xff000000UL) >> 24));
}

uint16_t htons(uint16_t n){
    return ((uint16_t)((((n) & (uint16_t)0x00ffU) << 8) | (((n) & (uint16_t)0xff00U) >> 8)));
}


const char *gai_strerror(int errcode){
    return NULL;
}

static int temp_idx = 0;

int socket(int domain, int type, int protocol){
    if (domain == AF_PACKET) {
        if (type == SOCK_RAW) {
            return temp_idx++;
        }
    }

    return 0;
}

int bind(int s, const struct sockaddr *name, socklen_t namelen){
    return 0;
}

int getsockname(int s, struct sockaddr *name, socklen_t *namelen){
    return 0;
}

int listen(int s, int backlog){
    return 0;
}
extern int tsw_recv_data_len_get(uint16_t *p_len);
int ioctl(int s, long cmd, void *argp){

    if (cmd == SIOCGIFHWADDR) {
        struct ifreq *p_ifr = (struct ifreq *)argp;

        memset(p_ifr->ifr_hwaddr.sa_data, 0, 14);

        if (strcmp(p_ifr->ifr_name, "/dev/eth_tsn0") == 0) {
            p_ifr->ifr_hwaddr.sa_data[0] = 0x01;
            p_ifr->ifr_hwaddr.sa_data[1] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[2] = 0x5e;
            p_ifr->ifr_hwaddr.sa_data[3] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[4] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[5] = 0x02;
        } else {
            p_ifr->ifr_hwaddr.sa_data[0] = 0x01;
            p_ifr->ifr_hwaddr.sa_data[1] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[2] = 0x5e;
            p_ifr->ifr_hwaddr.sa_data[3] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[4] = 0x00;
            p_ifr->ifr_hwaddr.sa_data[5] = 0x01;
        }
    } else if (cmd == FIONREAD) {
        int      *bytes_available = (int *)argp;
        uint16_t  len;

        int ret = tsw_recv_data_len_get(&len);
        if (ret != 0) {
            *bytes_available = 0;
        } else {
            *bytes_available = len - 16;
        }
//        int *bytes_available = (int *)argp;
//        *bytes_available = buf_len;
    }

    return 0;
}

int shutdown(int s, int how){
    return 0;
}

int poll(struct pollfd *fds, nfds_t nfds, int timeout){
    return 0;
}

const char * inet_ntop(int af, const void *src, char *dst, socklen_t size){
    return NULL;
}

int connect(int s, const struct sockaddr *name, socklen_t namelen){
    return 0;
}

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
            struct timeval *timeout){
    FD_ZERO(exceptset);
    return 0;
}

int pipe(int pipefd[2]){
    return 0;
}

int access(const char *pathname, int mode){
    return 0;
}

int gethostname(char *name, size_t len){
    return 0;
}
